package com.eternal.base.protocol;

import com.clj.fastble.data.BleDevice;
import com.eternal.base.database.entity.Device;
import com.eternal.base.global.BluetoothKey;
import com.eternal.base.utils.ByteUtils;
import com.eternal.base.utils.CRCUtil;
import com.eternal.base.utils.ScanRecord;
import com.eternal.framework.utils.KLog;

import java.nio.charset.StandardCharsets;

/**
 * author: liwc
 * created on: 2021-03-11
 * description:
 **/
public class BaseProtocol {
    private static final int SCAN_RECORD_LENGTH = 27;
    private static final byte[] HEAD = new byte[]{(byte) 0xA5, 0x00};

    private static void addInit(byte[] data, int pos, int x) {
        byte hei = (byte) ((x >> 8) & 0xff);
        byte low = (byte) (x & 0xff);
        data[pos] = hei;
        data[pos + 1] = low;
    }

    /**
     * 格式化数据为A5打头的数据包
     * 首字节 + 占位 + 数据长度 + 序号 + 校验码 + 占位符 + Command + 数据 + 校验码
     *
     * @param data        需要转换的数据包
     * @param commandType 命令  hex0x01--int-1--读取设备数据  hex0x02--int-2--读取设备数据（仅回复变化数据)
     *                    hex0x03--int-3--设置一个多个数据 hex0x11--int-17---读取历史日志
     *                    hex0x12--int-18--读取一组历史日志  hex0x13--int-19--结束读取历史日志
     *                    hex0x14--int-20--读取历史温湿度数据  hex0x15--int-21--读取一组温湿度数据
     *                    hex0x16--int-22--结束读取温湿度数据  hex-0x31--int-49--一组Automation
     *                    hex-0x32--int-50--一组Alarm hex-0x33--int-51--一组Notification
     * @return byte
     */
    protected static byte[] addHead(byte[] data, byte commandType, int sequence) {
        byte[] packet = new byte[12 + data.length];
        //固定头
        System.arraycopy(HEAD, 0, packet, 0, HEAD.length);
        //数据长度字节数组
        addInit(packet, 2, data.length);
        //当前数据序号字节数组
        addInit(packet, 4, sequence);
        //crc1
        byte[] crc = CRCUtil.crc16(packet, 0, 6);
        System.arraycopy(crc, 0, packet, 6, 2);
        //命令
        packet[8] = 0x00;
        packet[9] = commandType;
        //数据
        System.arraycopy(data, 0, packet, 10, data.length);
        //crc2
        crc = CRCUtil.crc16(packet, 8, 2 + data.length);
        System.arraycopy(crc, 0, packet, 10 + data.length, 2);
        return packet;
    }

    protected static byte[] check(byte[] packet) {
        byte[] data = new byte[packet.length - 10 - 2];
        System.arraycopy(packet, 10, data, 0, data.length);
        return data;
    }

    public static boolean checkResult(byte[] packet) {
        packet = check(packet);
        for (int i = 1; i < packet.length; i += 2) {
            if (packet[i] == 1) {
                return false;
            }
        }
        return true;
    }

    public static boolean checkSequence(byte[] packet, int sequence) {
        int num = (((packet[4] & 0xff) << 8) + (packet[5] & 0xff));
        KLog.e("check sequence:" + num + " sequence:" + sequence);
        return (((packet[4] & 0xff) << 8) + (packet[5] & 0xff)) == sequence;
    }

    public static int parseScanRecordType(BleDevice device) {
        byte[] scanRecord = ScanRecord.parseFromBytes(device.getScanRecord())
                .getManufacturerSpecificData(BluetoothKey.FEATURES);
        return scanRecord[12];
    }

    public static Device parseScanRecordData(BleDevice bleDevice) {
        byte[] scanRecord = ScanRecord.parseFromBytes(bleDevice.getScanRecord())
                .getManufacturerSpecificData(BluetoothKey.FEATURES);
        Device device = new Device(bleDevice.getMac());
        if (scanRecord != null && SCAN_RECORD_LENGTH == scanRecord.length) {
            device.typeName = new String(scanRecord, 6, 5, StandardCharsets.US_ASCII);
            //解析设备类型码
            device.type = scanRecord[12];
            switch (device.type) {
                case 1:
                case 2:
                    resoleABDevice(device, scanRecord);
                    break;
                case 4:
                case 5:
                    resoleCDevice(device, scanRecord);
                    break;
                default:
            }
            //解析当前时间
            device.connectTime = System.currentTimeMillis();
            return device;
        }
        return null;
    }

    private static void resoleCDevice(Device device, byte[] scanRecord) {
        byte bt = scanRecord[13];
        device.isDegree = !ByteUtils.getBit(bt, 1);
        device.tmpState = (byte) ByteUtils.getBits(bt, 4, 2);
        device.humState = (byte) ByteUtils.getBits(bt, 6, 2);
        device.tmp = ByteUtils.getShort(scanRecord, 15) * 10;
        device.hum = (scanRecord[17] & 0xff) * 100;
        bt = scanRecord[14];
        device.autoHighTmpSwitch = !ByteUtils.getBit(bt, 4);
        device.autoLowTmpSwitch = !ByteUtils.getBit(bt, 5);
        device.autoHighHumSwitch = !ByteUtils.getBit(bt, 6);
        device.autoLowHumSwitch = !ByteUtils.getBit(bt, 7);
        if (device.isDegree) {
            device.autoHighTmp = scanRecord[20];
            device.autoLowTmp = scanRecord[21];
        } else {
            device.autoHighTmp = scanRecord[18];
            device.autoLowTmp = scanRecord[19];
        }
        device.autoHighHum = scanRecord[22];
        device.autoLowHum = scanRecord[23];
    }

    private static void resoleABDevice(Device device, byte[] scanRecord) {
        byte bt = scanRecord[13];
        //解析当前设备的温度单位
        device.isDegree = !ByteUtils.getBit(bt, 1);
        //解析当前设备风扇档位变化
        device.fanState = (byte) ByteUtils.getBits(bt, 2, 2);
        //解析当前设备温度变化情况
        device.tmpState = (byte) ByteUtils.getBits(bt, 4, 2);
        //解析当前设备湿度变化情况
        device.humState = (byte) ByteUtils.getBits(bt, 6, 2);
        //当前实时温度
        device.tmp = ByteUtils.getShort(scanRecord, 14);
        //解析当前湿度
        device.hum = ByteUtils.getShort(scanRecord, 16);
        //解析当前风扇档位
        device.fan = scanRecord[18];
    }
}
